/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Beans;

import java.util.Calendar;
import javax.ejb.Stateless;
import Entity.*;
import Entity.Users;
import Helper.Helper_OutletReservation;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.Remote;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author AdminNUS
 */
@Stateless
@Remote
public class CustomerReservationBean implements CustomerReservationBeanRemote {

    @PersistenceContext()
    EntityManager em;

    @Override
    public Long AddUnconfirmedReservation(String customerEmail, Long outletId, Calendar date, Integer tsTime, String areaName, String comments) {
        OutletSeatArea area = new OutletSeatArea();
        Outlet ot = em.find(Outlet.class, outletId);
        int i = date.get(Calendar.DAY_OF_WEEK);
        int quota = 0;
        //find the area entity specified
        Query q1 = em.createQuery("SELECT c FROM OutletSeatArea c WHERE c.areaName = :paramAreaName  AND c.outletId = :paramOutlet");

        q1.setParameter("paramAreaName", areaName);
        q1.setParameter("paramOutlet", outletId);

        //??????????????????????area is a list?
        List arealist = q1.getResultList();
        area = (OutletSeatArea) arealist.get(0);


        //find the timeslot entity that have the specific tsTime and OutletSeatArea
        Query q2 = em.createQuery("SELECT a From Timeslot a WHERE a.tsTime = :paramTimeSlot AND a.area = :paramOutletSeatArea");

        q2.setParameter("paramTimeSlot", tsTime);
        q2.setParameter("paramOutletSeatArea", area);

        List tsList = q2.getResultList();
        Timeslot ts = (Timeslot) tsList.get(0);
        //get the quota for the day of the week of the specific timeslot entity
        quota = getDayofWeek(ts, date.get(Calendar.DAY_OF_WEEK));

        if (quota == -1) {
            System.out.println("Error Retrieve quota");
            return new Long(-1);
        }

        Long reservationId;

        boolean toCreateReservation = isWithinQuota(quota, date, tsTime, outletId, area.getAreaName());

        Users customers = new Users();

        if (toCreateReservation == true) {
            customers = getCustomerEntity(customerEmail);
            OutletReservation out = new OutletReservation();
            out.setCustomer(customers);
            out.setOutlet(ot);
            out.setTsTime(tsTime);
            out.setArea(area);
            out.setTimeslot(date);
            out.setComments(comments);
            if (ot.getAutoConfirmReservation()) {
                out.setConfirmStatus(true);
            }

            em.persist(out);
            ot.addReservations(out);
            em.persist(ot);
            reservationId = out.getId();
            return reservationId;

        } else //throw exception here
        {
            System.out.println("quota max");
            return new Long(-1);
        }
    }

    @Override
    public boolean editReservation(Long reservationId, Calendar timeslot, String areaName, String comments, Integer tsTime) {
        OutletReservation r = em.find(OutletReservation.class, reservationId);

        Outlet out = r.getOutlet();

        Query q1 = em.createQuery("SELECT c FROM OutletSeatArea c WHERE c.areaName = :paramAreaName  AND c.outletId = :paramOutlet");

        q1.setParameter("paramAreaName", areaName);
        q1.setParameter("paramOutlet", out.getId());

        List arealist = q1.getResultList();
        OutletSeatArea area = (OutletSeatArea) arealist.get(0);


        Query q2 = em.createQuery("SELECT a From Timeslot a WHERE a.tsTime = :paramTimeSlot AND a.area = :paramOutletSeatArea");

        q2.setParameter("paramTimeSlot", tsTime);
        q2.setParameter("paramOutletSeatArea", area);

        List tsList = q2.getResultList();
        Timeslot ts = (Timeslot) tsList.get(0);
        //get the quota for the day of the week of the specific timeslot entity
        Integer quota = getDayofWeek(ts, timeslot.get(Calendar.DAY_OF_WEEK));

        if (quota == -1) {
            System.out.println("Error Retrieve quota");
            return false;
        }

        boolean check = isWithinQuota(quota, timeslot, tsTime, out.getId(), area.getAreaName());


        if (check == true) {
            r.setArea(area);
            r.setComments(comments);
            r.setTimeslot(timeslot);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean cancelReservation(Long reservationId) {
        OutletReservation or = em.find(OutletReservation.class, reservationId);
        Users customer = or.getCustomer();
        List<OutletReservation> orl = customer.getReservations();

        if (orl.remove(or) == true) {
            customer.setReservations(orl);
            em.remove(or);
            return true;
        } else {
            return false;
        }

    }

    @Override
    public boolean checkQuota(String customerEmail, Long outletId, Calendar timeslot, String areaName, Integer tsTime) {

        OutletSeatArea area = new OutletSeatArea();
        Outlet ot = em.find(Outlet.class, outletId);
        int i = timeslot.get(Calendar.DAY_OF_WEEK);
        int quota = 0;
        //find the area entity specified
        Query q1 = em.createQuery("SELECT c FROM OutletSeatArea c WHERE c.areaName = :paramAreaName  AND c.outletId = :paramOutletID");

        q1.setParameter("paramAreaName", areaName);
        q1.setParameter("paramOutletID", outletId);

        List areaList =  q1.getResultList();
        area = (OutletSeatArea) areaList.get(0);
        //find the timeslot entity that have the specific tsTime and OutletSeatArea
        Query q2 = em.createQuery("SELECT a From Timeslot a WHERE a.tsTime = :paramTimeSlot AND a.area = :paramOutletSeatArea");

        q2.setParameter("paramTimeSlot", tsTime);
        q2.setParameter("paramOutletSeatArea", area);
        
        List tsList = q2.getResultList();
        Timeslot ts = (Timeslot) tsList.get(0);
        //get the quota for the day of the week of the specific timeslot entity
        quota = getDayofWeek(ts, timeslot.get(Calendar.DAY_OF_WEEK));

        if (quota == -1) {
            System.out.println("Error Retrieve quota");
            return false;
        }

        boolean toCreateReservation = isWithinQuota(quota, timeslot, tsTime, outletId, area.getAreaName());
        return toCreateReservation;
    }

    private boolean isWithinQuota(Integer quota, Calendar timeslot, Integer tsTime, Long outletId, String area) {

        Query q1 = em.createQuery("SELECT c FROM OutletReservation c WHERE c.timeslot =:paramDate AND c.tsTime = :paramTimeslot AND c.outlet.id = :paramOutlet AND c.area.areaName = :paramArea AND c.confirmStatus = :paramConfirm");

        q1.setParameter("paramDate", timeslot);
        q1.setParameter("paramTimeslot", tsTime);
        q1.setParameter("paramOutlet", outletId);
        q1.setParameter("paramArea", area);
        q1.setParameter("paramConfirm", true);

        List resultList = q1.getResultList();
        System.out.println("There are already " + resultList.size() + " confirmed booking existed");
        if (resultList.size() < quota) {
            return true;
        } else {
            return false;
        }

    }

    private Users getCustomerEntity(String email) {
        Query q = em.createQuery("SELECT c from Users c where c.email=:paramEmail ");
        q.setParameter("paramEmail", email);
        System.out.println("the email of the users is !!" + email);
        List<Users> customers = q.getResultList();

        Users cust = customers.get(0);
        return cust;
    }

    // Method to get all the reservations that a customer made from the current date
// ---------------------------------------------------------------------------------------------------------
    @Override
    public ArrayList<Helper_OutletReservation> getCurrentReservationsByCustomer(String customer) {

        ArrayList<Helper_OutletReservation> returnList = new ArrayList<Helper_OutletReservation>();
        Helper_OutletReservation helper = new Helper_OutletReservation();

        Calendar currentDate = Calendar.getInstance();

        Query q1 = em.createQuery("SELECT c FROM OutletReservation c WHERE c.customer.email = :paramCustomer");

        q1.setParameter("paramCustomer", customer);

        List resultList = q1.getResultList();

        for (Object o : resultList) {
            OutletReservation reservationEntity = (OutletReservation) o;
            if (currentDate.before(reservationEntity.getTimeslot())) {
                helper.setId(reservationEntity.getId());
                helper.setCustomerName(reservationEntity.getCustomer().getEmail());
                helper.setOutletName(reservationEntity.getOutlet().getOutletName());
                helper.setTimeslot(reservationEntity.getTimeslot());
                helper.setAreaName(reservationEntity.getArea().getAreaName());
                helper.setConfirmStatus(reservationEntity.getConfirmStatus());
                helper.setCustomerShowUp(reservationEntity.getCustomerShowUp());
                helper.setComments(reservationEntity.getComments());
                returnList.add(helper);

            }//end if
        }
        return returnList;
    }

    @Override
    public List<OutletReservation> getReservationByCustomerOutlet(String email, Long outletId) {
        Outlet outlet = em.find(Outlet.class, outletId);
        if (outlet == null) {
            return null;
        }

        List<OutletReservation> reservations = outlet.getReservations();

        if (reservations == null) {
            return null;
        }
        if (reservations.isEmpty()) {
            return null;
        }

        List<OutletReservation> returnList = new ArrayList<OutletReservation>();
        for (OutletReservation o : reservations) {
            if (o.getCustomer().getEmail().equals(email)) {
                returnList.add(o);
            }
        }

        return returnList;
    }

    @Override
    public List<OutletReservation> getReservationByDateOutlet(String dateStr, Long outletId) {
        Outlet outlet = em.find(Outlet.class, outletId);
        if (outlet == null) {
            return null;
        }
        List<OutletReservation> reservations = outlet.getReservations();
        if (reservations == null) {
            return null;
        }
        if (reservations.isEmpty()) {
            return null;
        }
        Calendar c2 = Calendar.getInstance();

        try {
            Date date = (new SimpleDateFormat("dd/MM/yyyy")).parse(dateStr);
            c2 = Calendar.getInstance();
            c2.setTime(date);
        } catch (Exception e) {
            return null;
        }

        List<OutletReservation> returnList = new ArrayList<OutletReservation>();
        for (OutletReservation o : reservations) {
            Calendar record = o.getTimeslot();
            
//            System.out.print("[" + record.get(Calendar.DATE) + "  vs  " + c2.get(Calendar.DATE) +  " ]");
            if (record.get(Calendar.DATE) == c2.get(Calendar.DATE)) {
                returnList.add(o); 
            }
        }

        return returnList;
    }

    @Override
    public void recordShowUp(Long outletId, Long id) {
        Outlet outlet = em.find(Outlet.class, outletId);
        if (outlet == null) {
            return;
        }

        List<OutletReservation> reservations = outlet.getReservations();
        for (OutletReservation o : reservations) {
            if (o.getId().equals(id)) {
                o.setCustomerShowUp(true);
                em.persist(o);
            }
        }
        em.persist(outlet);
    }

    @Override
    public void confirmReservation(Long outletId, Long id) {
        System.out.println("Confirming reservation.............");
        Outlet outlet = em.find(Outlet.class, outletId);
        if (outlet == null) {
            return;
        }

        OutletReservation re = em.find(OutletReservation.class, id);
        if (re == null) {
            return;
        }

        if (!outlet.getReservations().contains(re)) {
            return;
        }

        re.setConfirmStatus(true);
        em.persist(re);
        em.persist(outlet);
    }

    private int getDayofWeek(Timeslot ts, Integer i) {
        int quota = 0;
        if (i == 0) {
            quota = ts.getQuotaSun();
        } else if (i == 1) {
            quota = ts.getQuotaMon();
        } else if (i == 2) {
            quota = ts.getQuotaTue();
        } else if (i == 3) {
            quota = ts.getQuotaWed();
        } else if (i == 4) {
            quota = ts.getQuotaThu();
        } else if (i == 5) {
            quota = ts.getQuotaFri();
        } else if (i == 6) {
            quota = ts.getQuotaSat();
        } else {
            System.out.println("no quota set");
            return -1;
        }
        return quota;
    }
    
    
}
